﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PSIEpics;
using epics_server_remoting_class;
using JEpicsServer_driver;
using JtextEpicsInterface;
using System.Collections;


namespace jtext_EpicsServer
{
    /// <summary>
    /// Not big much different from its parent;
    /// bigest different is it's of the genuine type T.Type is fixed ,T
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class JEpicsRecord<T>:JEpicsRecord 
    {
        //EpicsServer_Remoting ParentRemoteServer;  //this will work with the ESRC(EpicsServer_Remoting) instead of the JEpicsServer
        //JEpicsDriver MyEJDriver; //each record has its own JEDriver this handles the hardware job

        //public string MyPvName;
        //Record_prop myRecordProp;   //the basic epics record property
        //RecordDriver myDriver;  //contain the driver info
        /// <summary>
        /// the raw value before proccessed by plugin,Type T
        /// </summary>
        public new  T  ValA;   //the raw value before proccessed by plugin
        /// <summary>
        /// the proccessed value  prossecced by plugin,Type T
        /// </summary>
        private  new  T ValB;  //the proccessed value  prossecced by plugin
        //private bool IsInput;   //if it is a input redoce if not it's a output

        //public delegate object  GetValFromHard(JEpicsRecord<T> myEJrecord);   //the dalagate to get a raw value from the hardware
        //GetValFromHard GetValHardHandler;

        //public delegate object SetValToHard(JEpicsRecord<T> myEJrecord);   //the dalagate to set a raw value to the hardware
        ////if it's a output record youwill need this   
        //SetValToHard SetValHardHandler;


        //public delegate object  RawToProcVal(JEpicsRecord<T> myEJrecord);       //proccess the raw value and get the ProcVal    
        ////you may always wants ProcVal=RawVal,you leave the  GetValHardHandler do the dirty work
        ////and the client do the fine work
        ////some times it may not like this
        //public RawToProcVal RawToProcHandler;   //in short R2P


        //public delegate object ProcToRawVal(JEpicsRecord<T> myEJrecord); //if it's a output record youwill need this   
        //public ProcToRawVal ProcToRawHandler;   //inshort P2R

        /// <summary>
        /// Initializes a new instance of the <see cref="JEpicsRecord&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="myRServer">the remotingserver.</param>
        /// <param name="my_RP">The recor property.</param>
        /// <param name="Driver">The driver.Note not the driver name but the driver intence</param>
        /// <param name="jeServer">The JtextEpics server.</param>
        public  JEpicsRecord(EpicsServer_Remoting myRServer,Record_prop my_RP,IJEDriver  Driver,JEpicsServer jeServer):base( myRServer,  my_RP)
        {
            //the constructor
            //initialize all things for this record
            //it may(most likely) read xml file which contains the record info
            //some of it is in base

            myRecordProp = my_RP;
            ParentRemoteServer.addRecord<T>(my_RP.pvName ,true,my_RP);

            #region Ini the driver and plugIn arguments
            
            //myDriverProp = my_RP;
            myDriver = Driver;
            //myPlugIN = PlugIn;
            myParentServer = jeServer;


            #endregion



            //test code
            //GetValHardHandler = new JEpicsRecord.GetValFromHard(DefaultGetHard);
            //RawToProcHandler = new JEpicsRecord.RawToProcVal(DefaultR2P);
            //IsInput = true;

        }

        #region initialize

        //public bool IniRecord()
        //{


        //}

        //public bool IniRecordDriver()   //ini the driver for this record usually ini a certain channel
        //{

        //    if (myDriver != null)
        //    {
        //        myDriver.IniChannel(myDriverProp);
        //        return true;
        //    }
        //    return false;

        //}

        #endregion

        #region test code

        /// <summary>
        /// not used
        /// </summary>
        /// <param name="myEJrecord">My E jrecord.</param>
        /// <returns></returns>
        static public object DefaultR2P(JEpicsRecord myEJrecord)
        {
            return ((JEpicsRecord<T>)myEJrecord).ValA;
        }

        /// <summary>
        /// not used
        /// </summary>
        /// <param name="myEJrecord">My E jrecord.</param>
        /// <returns></returns>
        static public object DefaultGetHard(JEpicsRecord myEJrecord)
        {
            object a =((JEpicsRecord<T>) myEJrecord).ValA;
            return (double)a+1;
        }

        #endregion


        /// <summary>
        /// Gets or sets the VAL.
        /// <para>this val is not the pv value,it the val the is not been proceessed by Pluguin</para>
        /// 	<para>For output this is equals to PV value ,youcan change this to meet the hardware output</para>
        /// 	<para>For input if the raw value from the hardware,you can this it will be put into PV later</para>
        /// </summary>
        /// <value>
        /// The VAL.
        /// </value>
        public override object VAL
        {
            get
            {
                return ValB;
            }
            set
            {
                ValB = (T)value;
            }
        }



        /// <summary>
        /// Gets or sets the PV value,not if it a input record it will override this PV value by VAL later-when flush-.
        /// </summary>
        /// <value>
        /// The PVAL.
        /// </value>
        public   override   object  PVAL
        {
           
            get
            {
                T tVal;
                tVal  = ParentRemoteServer.getRecord<T>(MyPvName);   //access the EpicsPv
                return tVal;
      
            }
            set 
            {
               T tVal;
               tVal=(T)value;
               ParentRemoteServer.setRecord<T>(MyPvName,tVal);
            }
        }




        #region flush


        /// <summary>
        /// <para>dont call this by  your self;</para>
        ///for input first hard->valA,,,
        ///for output first PV->vaLa
        /// </summary>
        public override void Flush()
        {
            //for input first hard->valA
            //for output first PV->vaLa
            if (IsRunning == false)
                return;

            if (IsInput == true)
            {
                //for input first hard->valA
                if (myDriver != null)
                {
                    ValA = (T)myDriver.GetVal(myRecordProp);
                    ValB = ValA;
                }
                else
                {
                    ValA = (T)PVAL; //no drivers
                    ValB = ValA;
                }
            }
            else
            {   //for output first PV->vaLa
                ValA = (T)PVAL;
                ValB = ValA;
                //Console.WriteLine("valb=" +ValB.ToString());
            }
        }


        //public override void callPlugin()
        //{

        //}

        /// <summary>
        /// Flush2s this instance.
        ///  <para>dont call this by  your self;</para>
        /// for input then valb->PV,,,
        /// for output then valB->hard
        /// </summary>
        public override void Flush2()
        {
            //for input then valb->PV
            //for output then valB->hard
            if (IsRunning == false)
                return;

            if (IsInput == true)
            {
                 //for input then valb->PV
                PVAL=ValB;
            }
            else
            {   //for output first PV->vaLa
                if (myDriver != null)
                {
                    myDriver.SetVal(myRecordProp, ValB);
                }
                else
                {
                    PVAL = ValB;
                    //Console.WriteLine("valB=" + ValB.ToString() + "pvname " + pvName);
                }
            }
        }


       


        #endregion
        /// <summary>
        /// dispose this record
        /// </summary>
        public override  void Dispose()
        {
            ParentRemoteServer.disposeRecord<T>(MyPvName);

            //stop scan thread here
        }




    }
}
